package cn.csg.iotplatform.module.system.controller.admin.permission;

import cn.csg.iotplatform.framework.common.enums.CommonStatusEnum;
import cn.csg.iotplatform.framework.common.pojo.CommonResult;
import cn.csg.iotplatform.framework.common.pojo.PageResult;
import cn.csg.iotplatform.framework.web.core.util.WebFrameworkUtils;
import cn.csg.iotplatform.module.system.api.permission.dto.UserZoneDomainDto;
import cn.csg.iotplatform.module.system.controller.admin.permission.vo.permission.PermissionAssignRoleDataScopeReqVO;
import cn.csg.iotplatform.module.system.controller.admin.permission.vo.permission.PermissionAssignRoleMenuReqVO;
import cn.csg.iotplatform.module.system.controller.admin.permission.vo.permission.PermissionAssignUserRoleReqVO;
import cn.csg.iotplatform.module.system.controller.admin.permission.vo.permission.RoleUserListReqDto;
import cn.csg.iotplatform.module.system.controller.admin.permission.vo.role.UserRolesReqDto;
import cn.csg.iotplatform.module.system.controller.admin.permission.vo.role.UserRolesRespVo;
import cn.csg.iotplatform.module.system.controller.admin.user.vo.user.CopyUsersRolesDto;
import cn.csg.iotplatform.module.system.controller.admin.user.vo.user.PageCopyUserRoleDto;
import cn.csg.iotplatform.module.system.controller.admin.user.vo.user.PageCopyUserRoleVo;
import cn.csg.iotplatform.module.system.controller.admin.user.vo.user.UserSimpleRespVO;
import cn.csg.iotplatform.module.system.dal.dataobject.permission.MenuDO;
import cn.csg.iotplatform.module.system.dal.dataobject.permission.RoleMenuDO;
import cn.csg.iotplatform.module.system.dal.dataobject.permission.UserRoleDO;
import cn.csg.iotplatform.module.system.dal.dataobject.user.AdminUserDO;
import cn.csg.iotplatform.module.system.dal.mysql.permission.MenuMapper;
import cn.csg.iotplatform.module.system.dal.mysql.permission.RoleMenuMapper;
import cn.csg.iotplatform.module.system.dal.mysql.permission.UserRoleMapper;
import cn.csg.iotplatform.module.system.dal.mysql.user.AdminUserMapper;
import cn.csg.iotplatform.module.system.service.permission.PermissionService;
import cn.csg.iotplatform.module.system.service.tenant.TenantService;
import cn.csg.iotplatform.module.system.util.ToolUtil;
import cn.hutool.core.collection.CollUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.tags.Tag;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;

import javax.annotation.Resource;
import javax.validation.Valid;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;

import static cn.csg.iotplatform.framework.common.exception.util.ServiceExceptionUtil.exception;
import static cn.csg.iotplatform.framework.common.pojo.CommonResult.success;
import static cn.csg.iotplatform.module.system.enums.ErrorCodeConstants.*;

/**
 * 权限 Controller，提供赋予用户、角色的权限的 API 接口
 *
 * @author 芋道源码
 */
@Tag(name = "管理后台 - 权限")
@RestController
@RequestMapping("/system/permission")
public class PermissionController {

    @Resource
    private PermissionService permissionService;
    @Resource
    private TenantService tenantService;
    @Resource
    private AdminUserMapper adminUserMapper;
    @Resource
    private UserRoleMapper userRoleMapper;
    @Resource
    private RoleMenuMapper roleMenuMapper;
    @Resource
    private MenuMapper menuMapper;

    @Operation(summary = "获得角色拥有的菜单编号")
    @Parameter(name = "roleId", description = "角色编号", required = true)
    @GetMapping("/list-role-menus")
    @PreAuthorize("@ss.hasPermission('system:permission:assign-role-menu')")
    public CommonResult<Set<Long>> getRoleMenuList(Long roleId) {
        return success(permissionService.getRoleMenuListByRoleId(roleId));
    }

    @PostMapping("/assign-role-menu")
    @Operation(summary = "赋予角色菜单")
    @PreAuthorize("@ss.hasPermission('system:permission:assign-role-menu')")
    public CommonResult<Boolean> assignRoleMenu(@Validated @RequestBody PermissionAssignRoleMenuReqVO reqVO) {
        // 开启多租户的情况下，需要过滤掉未开通的菜单
        tenantService.handleTenantMenu(menuIds -> reqVO.getMenuIds().removeIf(menuId -> !CollUtil.contains(menuIds, menuId)));

        //判断是否存在越权菜单编号
        Long userId = WebFrameworkUtils.getLoginUserId();
        AdminUserDO adminUserDO = adminUserMapper.selectById(userId);
        if (adminUserDO == null){
            throw exception(USER_NOT_EXISTS);
        }

        LambdaQueryWrapper<UserRoleDO> queryUserRoleWrapper = new LambdaQueryWrapper<UserRoleDO>().eq(UserRoleDO::getUserId, userId);
        List<UserRoleDO> userRoleDOS = userRoleMapper.selectList(queryUserRoleWrapper);
        boolean isSuperAdmin = userId == 1;
        if (isSuperAdmin){
            // 执行菜单的分配
            permissionService.assignRoleMenu(reqVO.getRoleId(), reqVO.getMenuIds());
            return success(true);
        }

        List<Long> userRoleIds = userRoleDOS.stream().map(UserRoleDO::getRoleId).collect(Collectors.toList());
        if (userRoleIds.isEmpty()){
            throw exception(ROLE_NOT_EXISTS);
        }

        LambdaQueryWrapper<RoleMenuDO> queryRoleMenuWrapper = new LambdaQueryWrapper<RoleMenuDO>()
                .in(RoleMenuDO::getRoleId, userRoleIds);
        List<RoleMenuDO> roleMenuDOS = roleMenuMapper.selectList(queryRoleMenuWrapper);
        List<Long> userMenuIds = roleMenuDOS.stream().map(RoleMenuDO::getMenuId).collect(Collectors.toList());
        if (userMenuIds.isEmpty()){
            throw exception(ROLE_NOT_ASSOCIATED_WITH_MENU);
        }

        LambdaQueryWrapper<MenuDO> queryMenuWrapper = new LambdaQueryWrapper<MenuDO>()
                .eq(MenuDO::getStatus, CommonStatusEnum.ENABLE.getStatus())
                .in(MenuDO::getId, userMenuIds)
                .orderByAsc(MenuDO::getSort);
        List<MenuDO> menuDOList = menuMapper.selectList(queryMenuWrapper);
        Map<Long, MenuDO> userPermitMenuMap = menuDOList.stream().collect(Collectors.toMap(MenuDO::getId, menuDO -> menuDO));

        boolean allMatch = reqVO.getMenuIds().stream().allMatch(v -> userPermitMenuMap.containsKey(v));
        if (!allMatch){
            throw exception(EXIST_USER_NO_PERMISSION_MENU);
        }
        // 执行菜单的分配
        permissionService.assignRoleMenu(reqVO.getRoleId(), reqVO.getMenuIds());
        return success(true);
    }

    @PostMapping("/assign-role-data-scope")
    @Operation(summary = "赋予角色数据权限")
    @PreAuthorize("@ss.hasPermission('system:permission:assign-role-data-scope')")
    public CommonResult<Boolean> assignRoleDataScope(@Valid @RequestBody PermissionAssignRoleDataScopeReqVO reqVO) {
        permissionService.assignRoleDataScope(reqVO.getRoleId(), reqVO.getDataScope(), reqVO.getDataScopeDeptIds());
        return success(true);
    }

    @Operation(summary = "获得管理员拥有的角色编号列表")
    @Parameter(name = "userId", description = "用户编号", required = true)
    @GetMapping("/list-user-roles")
    @PreAuthorize("@ss.hasPermission('system:permission:assign-user-role')")
    public CommonResult<Set<Long>> listAdminRoles(@RequestParam("userId") Long userId) {
        return success(permissionService.getUserRoleIdListByUserId(userId));
    }

    @Operation(summary = "赋予用户角色")
    @PostMapping("/assign-user-role")
    @PreAuthorize("@ss.hasPermission('system:permission:assign-user-role')")
    public CommonResult<Boolean> assignUserRole(@Validated @RequestBody PermissionAssignUserRoleReqVO reqVO) {
        Long userId = WebFrameworkUtils.getLoginUserId();
        permissionService.assignUserRoleNewVersion(reqVO.getUserId(), reqVO.getRoleIds(),userId);
        return success(true);
    }

    @Operation(summary = "获得角色关联的用户信息列表")
    @GetMapping("/list-role-users")
    @PreAuthorize("@ss.hasPermission('system:permission:list-role-users')")
    public CommonResult<PageResult<UserSimpleRespVO>> listRoleUsers(RoleUserListReqDto dto) {
        return success(permissionService.getRoleUserListByRoleId(dto));
    }

    @Operation(summary = "关联角色列表")
    @GetMapping("/page-user-roles")
    @PreAuthorize("@ss.hasPermission('system:permission:page-user-roles')")
    public CommonResult<PageResult<UserRolesRespVo>> pageUserRoles(UserRolesReqDto dto) {
        return success(permissionService.pageUserRolesNewVersion(dto));
    }

    @Operation(summary = "查询用户分区领域权限(设备授权)")
    @Parameter(name = "userId", description = "用户编号", required = true)
    @GetMapping("/user-zones-domains")
    @PreAuthorize("@ss.hasPermission('systemManagement:user:user-zones-domains')")
    public CommonResult<Object> queryUserZoneDomains(@RequestParam("userId") Long userId) {
        return success(permissionService.queryUserZoneDomains(userId));
    }

    @Operation(summary = "授权用户分区领域权限(设备授权)")
    @PostMapping("/assign-user-zones-domains")
    @PreAuthorize("@ss.hasPermission('systemManagement:user:assign-user-zones-domains')")
    public CommonResult<Boolean> assignUserZoneDomains(@Validated @RequestBody UserZoneDomainDto dto) {
        permissionService.assignUserZoneDomains(dto);
        return success(true);
    }

    @Operation(summary = "分页查询权限复制(设备权限)")
    @GetMapping("/page-copy-user-roles")
    @PreAuthorize("@ss.hasPermission('system:permission:page-copy-user-roles')")
    public CommonResult<PageResult<PageCopyUserRoleVo>> pageCopyUserRoles(PageCopyUserRoleDto dto) {
        return success(permissionService.pageCopyUserRoles(dto));
    }

    @PostMapping("/copy-user-roles")
    @Operation(summary = "权限复制(设备授权)")
    @PreAuthorize("@ss.hasPermission('systemManagement:permission:copy-user-roles')")
    public CommonResult<Boolean> copyUserRoles(@Validated @RequestBody CopyUsersRolesDto dto) {
        if (ToolUtil.isOneEmpty(dto.getTargetUserIds(), dto.getSourceUserId())) {
            return CommonResult.error(USER_NOT_EXISTS);
        }
        this.permissionService.copyUserRoles(dto);
        return success(true);
    }

/*    @PostMapping("/copy-users-roles")
    @Operation(summary = "（旧）权限复制(设备授权)")
    @PreAuthorize("@ss.hasPermission('systemManagement:permission:copy-users-roles')")
    public CommonResult<Boolean> copyUsersRoles(@Validated @RequestBody CopyUsersRolesDto dto) {
        if (ToolUtil.isOneEmpty(dto.getTargetUserId(), dto.getSourceUserIds())) {
            return CommonResult.error(ErrorCodeConstants.USER_NOT_EXISTS);
        }
        this.permissionService.copyUserRoles(dto);
        return success(true);
    }*/

}
